package jmpo.strm;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

/**
 * Рассмтрим простейшие источники, которые могут быть у потока данных в Stream API.
 */
public class BasicSourceStream {
    // коллекция - unordered stream
    private static void collectionSourceTest() {
        Set<String> strings = new HashSet<>();
        strings.add(new String("abba"));
        strings.add(new String("cadabba"));
        strings.add(new String("mabuza"));
        strings.add(new String("lamuzza"));

        Stream<String> strstream = strings.stream();
        strstream.parallel().sequential().map(s -> s.substring(3)).forEach(System.out::println);
    }

    // из набора элементов - unordered stream
    private static void immutableCollectionSourceTest() {
        var strstream = Stream.of("abba", "caddabba", "mabuza", "lamuzza");
        strstream.parallel().sequential().map(s -> s.substring(3)).forEach(System.out::println);
    }

    // из массива - unordered stream
    private static void arraySourceTest() {
        String data = "abba caddabba mabuza lamuzza";
        Arrays.stream(data.split(" ")).parallel().sequential().map(s -> s.substring(3)).forEach(System.out::println);
    }

    // если вам необходимо создать большое количество элементов, а затем запустить поток данных,
    // можно сразу добавлять их в поток с использованием Stream.Builder
    private static void streamBuilderSourceTest() {
        Stream.Builder<String> builder = Stream.builder();
        for (int i = 0; i != 10; ++i)
            builder.accept(new String("a"));
        builder.build().map(s -> s + s).forEach(System.out::println);
    }

    // из файла с помощью lines - ordered stream
    private static void fileSourceTest(String filename) throws IOException {
        try (var br = new BufferedReader(new FileReader(filename))) {
            var lineStream = br.lines();
            lineStream.map(s -> s.length()).forEach(System.out::println);
        }
    }
    /**
     * Обратим внимание, что Stream реализует AutoClosable, так что мы могли избежать создания временного буфера
     * и сразу получить строки из файла
     */
    private static void fileCloseSourceTest(String filename) throws IOException {
        try (var lines = new BufferedReader(new FileReader(filename)).lines()) {
            lines.map(s -> s.length()).forEach(System.out::println);
        }
    }

    /**
     * Можно создавать бесконечные потоки с помощью генераторов.
     * Важно отметить, что для работы с бесконечными потоками нам понадобятся
     * специальные методы, в частности limit, иначе их обработка не завершится.
     */
    // generate создаёт неупорядоченный поток данных
    private static void generateSourceTest() {
        final StringBuffer sb = new StringBuffer();
        Stream<String> strstream = Stream.generate(() -> sb.append("a").toString());
        strstream.map(s -> s.length()).limit(100).forEach(System.out::println);
    }

    // iterate создаёт упорядоченный поток данных
    private static void iterateSourceTest() {
        Stream<String> strstream = Stream.iterate("a", s -> s + "a" );
        strstream.map(s -> s.length()).limit(100).forEach(System.out::println);
    }

    public static void main(String[] args) throws IOException {
        if (false) collectionSourceTest();
        if (false) immutableCollectionSourceTest();
        if (false) arraySourceTest();
        if (false) streamBuilderSourceTest(); 
        if (false) fileSourceTest(args[0]);
        if (false) fileCloseSourceTest(args[0]);
        if (false) generateSourceTest();
        if (false) iterateSourceTest(); 
    } 
}
